package io.summer.basis.excepts;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import javax.servlet.http.HttpServletRequest;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.boot.autoconfigure.web.servlet.error.ErrorViewResolver;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;

import io.summer.basis.api.ApiResponse;
import lombok.extern.slf4j.Slf4j;

/**
 * @author ml
 */
@Controller
@Slf4j
public class MyErrorController extends BasicErrorController {
  @Autowired
  private ObjectMapper objectMapper;

  public MyErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties, List<ErrorViewResolver> errorViewResolvers) {
    super(errorAttributes, serverProperties.getError(), errorViewResolvers);
  }

  @Override
  public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
    HttpStatus status = getStatus(request);
    if (status == HttpStatus.NO_CONTENT) {
      return new ResponseEntity<>(status);
    }
    ApiResponse<?> response;
    Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");
    if (Objects.nonNull(throwable)) {
      response = ApiResponse.fail(throwable.getMessage());
    } else {
      switch (status) {
        case FORBIDDEN:
        case UNAUTHORIZED:
        case BAD_REQUEST:
        case MOVED_PERMANENTLY:
          response = ApiResponse.fail(status.getReasonPhrase());
          break;
        default:
          response = ApiResponse.fail("unexpected error. are you get lost?");
          break;
      }
    }
    Map<String, Object> body = null;
    try {
      JavaType javaType = objectMapper.getTypeFactory().constructParametricType(Map.class, String.class, Object.class);
      body = objectMapper.convertValue(response, javaType);
    } catch (IllegalArgumentException e) {
      log.error("MyErrorController: ", e);
    }
    if (log.isDebugEnabled()) {
      log.error("MyErrorController occur: {}", body);
    }
    return new ResponseEntity<>(body, status);
  }
}
